/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_t5t.c
 * @brief T5T tag ndef implementation
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW_T5T)

#include "rw_tag.h"
#include "nfc_log_api.h"
#include "discover_int.h"
#include "nfc_hex_utils.h"
#include "rw_int.h"
#include "rw_t5t_common.h"

tT5T_INFO s_t5t_info;

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

static tNCI_STATUS rw_i93_ndef_check_cc(void);
static tNCI_STATUS rw_i93_ndef_search_tlv(void);
static tNCI_STATUS rw_i93_ndef_check_lock_status(void);
static tNCI_STATUS rw_i93_ndef_reset_tlv_block();
static tNCI_STATUS rw_i93_ndef_write_blocks(void);
static tNCI_STATUS rw_i93_ndef_update_length(void);
static tNCI_STATUS rw_i93_write_cc_ndef_tlv(void);
static tNCI_STATUS rw_i93_check_ndef_writable(void);
static tNCI_STATUS rw_i93_set_tag_read_only_if_ndef_detected(void);
static tNCI_STATUS rw_i93_update_cc_read_only(void);
static tNCI_STATUS rw_i93_lock_ndef_tlv(void);

static tNCI_STATUS rw_t5t_ndef_reset_tlv_block(void);
static tNCI_STATUS rw_t5t_ndef_write_blocks(void);
static tNCI_STATUS rw_t5t_ndef_update_length(void);
static tNCI_STATUS rw_t5t_ndef_search_tlv(void);
static tNCI_STATUS rw_t5t_ndef_check_cc(void);
static tNCI_STATUS rw_t5t_set_tag_read_only_if_ndef_detected(void);
static tNCI_STATUS rw_t5t_update_cc_read_only(void);
static tNCI_STATUS rw_t5t_lock_ndef_tlv(void);

static tNCI_STATUS is_ndef_formatable();
static tNCI_STATUS ndef_format();
static tNCI_STATUS ndef_write(uint8_t *p_data, uint32_t len);
static tNCI_STATUS ndef_read(tNCI_RSP *p_rsp);
static tNCI_STATUS ndef_detect(tNCI_RW_NDEF_INFO *p_ndef_info);
static tNCI_STATUS set_tag_read_only(bool is_hard_lock);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
static tNCI_STATUS on_disconnect();
static tNCI_STATUS on_connect(tNCI_RW_TAG *p_tag);
static tNCI_STATUS presence_check();
static tNCI_STATUS check_transceive_resp(uint8_t *p_rsp, uint16_t *p_rsp_len);

#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

static tNCI_STATUS rw_i93_lock_ndef_tlv(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    uint8_t block_number;
    NFCLOG_D("enter");
    NFCLOG_D("ndef tlv start offset(%d), last offset(%d)",
                p_i93->ndef_tlv_start_offset, p_i93->ndef_tlv_last_offset);
    /* successfully write CC then lock all blocks of NDEF TLV */
    p_i93->rw_offset = p_i93->ndef_tlv_start_offset;


    /* if we need to lock more blocks */
    while (p_i93->rw_offset < p_i93->ndef_tlv_last_offset) {
        if (0 == p_i93->block_size) {
            NFCLOG_E("invalid block size");
            status = NCI_STATUS_EXT_FAILED;
            return status;
        }
        NFCLOG_D("rw offset(%d)", p_i93->rw_offset);
        block_number = (uint8_t)(p_i93->rw_offset / p_i93->block_size);
        status = rw_i93_send_cmd_lock_block(block_number);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("lock block(%d) failed", block_number);
            return status;
        }
        p_i93->rw_offset += p_i93->block_size;
    }
    /* if the first block of NDEF TLV is different from block of CC */
    if (p_i93->ndef_tlv_start_offset / p_i93->block_size != 0) {
        /* lock block of CC */
        status = rw_i93_send_cmd_lock_block(0);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("lock cc block failed");
            return status;
        }
    }
    p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
    status = NCI_STATUS_OK;

    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS rw_i93_update_cc_read_only(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    uint8_t *p_rsp_data;
    uint16_t length = 0;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    NFCLOG_D("enter");

    /* get CC in the first block */
    status = rw_i93_send_cmd_read_single_block(0, false, p_rsp);
    if (status != NCI_STATUS_OK) {
        goto exit;
    }
    p_rsp_data = p_rsp->data;
    length = p_rsp->len;
    p_rsp_data++;
    length--;

    if (length < RW_I93_CC_SIZE) {
        NFCLOG_E("invlid cc length:%d", length);
        status = NCI_STATUS_EXT_FAILED;
        goto exit;
    }
    /* mark CC as read-only */
    *(p_rsp_data + 1) |= I93_ICODE_CC_READ_ONLY;

    if (length < p_i93->block_size) {
        NFCLOG_E("invlid length(%d) < block size(%d)", length, p_i93->block_size);
        status = NCI_STATUS_EXT_FAILED;
        goto exit;
    }
    status = rw_i93_send_cmd_write_single_block(0, p_rsp_data);
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("wirte single block failed");
        goto exit;
    }

exit:
    free_nci_buf(p_rsp);
    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS rw_i93_set_tag_read_only_if_ndef_detected(void) {

    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    NFCLOG_D("enter");
    status = rw_i93_update_cc_read_only();
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("update cc read only failed");
        return status;
    }

    status = rw_i93_lock_ndef_tlv();
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("lock ndef tlv failed");
        return status;
    }

    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS rw_t5t_update_cc_read_only(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    uint8_t cc_blk0[4];
    NFCLOG_D("enter");
    if (!osi_memcpy_s(cc_blk0, RW_I93_CC_SIZE, p_i93->gre_cc_content, RW_I93_CC_SIZE)) {
        NFCLOG_E("copy cc data failed");
        return NCI_STATUS_EXT_COPY_FAILED;
    }

    /* mark CC as read-only */
    *(cc_blk0 + 1) |= I93_ICODE_CC_READ_ONLY;
       NFCLOG_I("Set CC1 to RO - cc[0]=0x%02x, cc[1]=0x%02x, "
        "cc[2]=0x%02x, cc[3]=0x%02x",
        *cc_blk0, *(cc_blk0 + 1), *(cc_blk0 + 2), *(cc_blk0 + 3));

    status = rw_i93_send_cmd_write_single_block(0, cc_blk0) ;

    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS rw_t5t_lock_ndef_tlv(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    uint16_t block_number;
    NFCLOG_D("enter");
    NFCLOG_D("t5t area last offset(%d)", p_i93->t5t_area_last_offset);
    /* successfully write CC then lock CC and all blocks of T5T Area */
    p_i93->rw_offset = 0;

    while(p_i93->rw_offset <= p_i93->t5t_area_last_offset) {
        if (p_i93->block_size == 0) {
            NFCLOG_D("zero block_size error");
            status = NCI_STATUS_EXT_FAILED;
            return status;
        }
        NFCLOG_D("rw offset(%d)", p_i93->rw_offset);
        /* get the next block of NDEF TLV */
        block_number = (uint16_t)(p_i93->rw_offset / p_i93->block_size);

        if (!g_dta_mode_enabled && block_number > p_i93->num_block - 1) {
            NFCLOG_I("t5t lock ndef tlv done, block number(%d) is outside of numbers of block(%d)",
                        block_number, p_i93->num_block);
            break;
        }
        status = rw_i93_send_cmd_lock_block(block_number);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("lock block(%d) failed", block_number);
            return status;
        }
        p_i93->rw_offset += p_i93->block_size;

    }

    p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
    status = NCI_STATUS_OK;

    NFCLOG_D("exit");
    return status;
}


static tNCI_STATUS rw_t5t_set_tag_read_only_if_ndef_detected(void) {
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    NFCLOG_D("enter");
    status = rw_t5t_update_cc_read_only();

    if (status != NCI_STATUS_OK) {
        NFCLOG_E("update cc read only failed");
        return status;
    }

    status = rw_t5t_lock_ndef_tlv();
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("lock ndef tlv failed");
        return status;
    }

    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS rw_t5t_ndef_check_cc(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint16_t length = 0;
    uint8_t *p_rsp_data;
    uint8_t cc[8];
    uint32_t t5t_area_len = 0;
    NFCLOG_D("enter");

    status = rw_i93_send_cmd_read_single_block(0, false, p_rsp);
    if (status != NCI_STATUS_OK) {
        goto exit;
    }
    p_rsp_data = p_rsp->data;
    length = p_rsp->len;
    p_rsp_data++;
    length--;

    if (length < RW_I93_CC_SIZE) {
        NFCLOG_E("invlid cc size:%d", length);
        status = NCI_STATUS_EXT_FAILED;
        goto exit;
    }

    STREAM_TO_ARRAY(cc, p_rsp_data, RW_I93_CC_SIZE);
    /*
    ** Capability Container (CC)
    **
    ** CC[0] : magic number (0xE1)
    ** CC[1] : Bit 7-6:Major version number
    **       : Bit 5-4:Minor version number
    **       : Bit 3-2:Read access condition (00b: read access granted
    **         without any security)
    **       : Bit 1-0:Write access condition (00b: write access granted
    **         without any security)
    ** CC[2] : Memory size in 8 bytes (Ex. 0x04 is 32 bytes) [STM, set to
    **         0xFF if more than 2040bytes]
    ** CC[3] : Bit 0:Read multiple blocks is supported [NXP, STM]
    **       : Bit 1:Inventory page read is supported [NXP]
    **       : Bit 2:More than 2040 bytes are supported [STM]
    */
    NFCLOG_D("cc[0-3]: 0x%02X 0x%02X 0x%02X 0x%02X", cc[0], cc[1], cc[2], cc[3]);

    if ((cc[0] == I93_ICODE_CC_MAGIC_NUMER_E1) ||
        (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2)) {
        if ((cc[1] & 0xC0) > I93_VERSION_1_x) {
            NFCLOG_D("Major mapping version above 1 %d.x", cc[1] >> 6);
            /* major mapping version above 1 not supported */
            NFCLOG_E("major mapping version above 1");
            status = NCI_STATUS_EXT_FAILED;
            goto exit;
        }
        if ((cc[1] & I93_ICODE_CC_READ_ACCESS_MASK) ==
            I93_ICODE_CC_READ_ACCESS_GRANTED) {
            if ((cc[1] & I93_ICODE_CC_WRITE_ACCESS_MASK) !=
                I93_ICODE_CC_WRITE_ACCESS_GRANTED) {
                /* read-only or password required to write */
                p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
            }
            if (cc[3] & I93_ICODE_CC_MBREAD_MASK) {
                /* tag supports read multiple blocks command */
                p_i93->intl_flags |= RW_I93_FLAG_READ_MULTI_BLOCK;
            }
            if (cc[3] & I93_ICODE_CC_SPECIAL_FRAME_MASK) {
                /* tag supports Special Frame for Write-Alike commands */
                p_i93->intl_flags |= RW_I93_FLAG_SPECIAL_FRAME;
            }
            /* get block size from length of the first READ_SINGLE_BLOCK response
            */
            if (length == I93_BLEN_4BYTES)
                p_i93->block_size = I93_BLEN_4BYTES;
            else if (length == I93_BLEN_8BYTES)
                p_i93->block_size = I93_BLEN_8BYTES;
            else if (length == I93_BLEN_16BYTES)
                p_i93->block_size = I93_BLEN_16BYTES;
            else if (length == I93_BLEN_32BYTES)
                p_i93->block_size = I93_BLEN_32BYTES;
            else {
                NFCLOG_E("covert length to block size failed");
                status = NCI_STATUS_EXT_FAILED;
                goto exit;
            }
            /* T5T_Area length = 8 * MLEN */
            if (cc[2] == 0) {
                /* CC is 8-byte, MLEN is defined by bytes 6 & 7 */
                if (length >= I93_BLEN_8BYTES) {
                    STREAM_TO_ARRAY(&cc[4], p_rsp_data, RW_I93_CC_SIZE);
                    NFCLOG_D("cc[4-7]: 0x%02X 0x%02X 0x%02X 0x%02X",
                                cc[4], cc[5], cc[6], cc[7]);
                    t5t_area_len = cc[7] + (cc[6] << 8);
                    t5t_area_len <<= 3;
                    if (!g_dta_mode_enabled) {
                        // 只在非dta模式下才减去CC的长度
                        t5t_area_len = t5t_area_len - 8;
                    }
                    p_i93->t5t_area_last_offset = t5t_area_len + 8 - 1;
                    p_i93->max_ndef_length = t5t_area_len;
                    p_i93->t5t_area_start_block = 1;

                    if (!osi_memcpy_s(p_i93->gre_cc_content, RW_I93_CC_SIZE_8, cc, RW_I93_CC_SIZE_8)) {
                        NFCLOG_E("osi memcpy failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        goto exit;
                    }
                } else {
                    /* require an additional read to get the second half of the
                    * CC from block 1 */
                    NFCLOG_D("read the second half of the CC from block 1");
                    if (!osi_memcpy_s(p_i93->gre_cc_content, RW_I93_CC_SIZE, cc, RW_I93_CC_SIZE)) {
                        NFCLOG_E("osi memcpy failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        goto exit;
                    }
                    reset_nci_buf(p_rsp);
                    status = rw_i93_send_cmd_read_single_block(1, false, p_rsp);
                    if (status != NCI_STATUS_OK) {
                        goto exit;
                    }
                    p_rsp_data = p_rsp->data;
                    length = p_rsp->len;
                    p_rsp_data++;
                    length--;

                    if (length < RW_I93_CC_SIZE) {
                        NFCLOG_E("invlid cc size:%d", length);
                        status = NCI_STATUS_EXT_FAILED;
                        goto exit;
                    }

                    STREAM_TO_ARRAY(cc, p_rsp_data, RW_I93_CC_SIZE);
                    /*
                    ** Capability Container (CC) second block
                    **
                    ** CC[4] : RFU
                    ** CC[5] : RFU
                    ** CC[6] : MSB MLEN
                    ** CC[7] : LSB MLEN
                    */

                    NFCLOG_D("second block:cc[4-7]: 0x%02X 0x%02X 0x%02X 0x%02X",
                                cc[0], cc[1], cc[2], cc[3]);

                    /* T5T_Area length = 8 * MLEN */
                    /* CC is 8-byte, MLEN is defined by bytes 6 & 7 */
                    t5t_area_len = cc[3] + (cc[2] << 8);
                    t5t_area_len <<= 3;
                    if (!g_dta_mode_enabled) {
                        // 只在非dta模式下才减去CC的长度
                        t5t_area_len = t5t_area_len - 8;
                    }
                    p_i93->max_ndef_length = t5t_area_len;

                    p_i93->t5t_area_last_offset = t5t_area_len + 8 - 1;
                    if (!osi_memcpy_s(&(p_i93->gre_cc_content[4]), RW_I93_CC_SIZE, cc, RW_I93_CC_SIZE)) {
                        NFCLOG_E("osi memcpy failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        goto exit;
                    }
                    p_i93->num_block = t5t_area_len / p_i93->block_size;
                    p_i93->t5t_area_start_block = 2;

                    NFCLOG_D("T5T Area size:%d, Nb blocks:0x%04X, Block size:0x%02X, "
                        "T5T Area last offset:%d",
                        t5t_area_len, p_i93->num_block, p_i93->block_size,
                        p_i93->t5t_area_last_offset);
                }
            } else {
                /* CC is 4-byte, MLEN is defined by byte 2 */
                t5t_area_len = cc[2] << 3;
                if (!g_dta_mode_enabled) {
                    // 只在非dta模式下才减去CC的长度
                    t5t_area_len = t5t_area_len - 4;
                }
                p_i93->t5t_area_last_offset = t5t_area_len + 4 - 1;
                p_i93->t5t_area_start_block = 1;
                if (!osi_memcpy_s(p_i93->gre_cc_content, RW_I93_CC_SIZE, cc, RW_I93_CC_SIZE)) {
                    NFCLOG_E("osi memcpy failed %d", __LINE__);
                    status = NCI_STATUS_EXT_FAILED;
                    goto exit;
                }
            }
            p_i93->num_block = t5t_area_len / p_i93->block_size;
            p_i93->max_ndef_length = t5t_area_len;
            if (p_i93->gre_cc_content[0] == I93_ICODE_CC_MAGIC_NUMER_E2) {
                /* can only be done here if CC is coded over 4 bytes */
                p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
            }
            NFCLOG_E("T5T Area size:%d, Nb blocks:0x%04X, "
                "Block size:0x%02X, T5T Area last offset:%d",
                t5t_area_len, p_i93->num_block, p_i93->block_size,
                p_i93->t5t_area_last_offset);
        }
    }

    if( (0 == p_i93->gre_cc_content[2] && p_i93->block_size > I93_BLEN_8BYTES)
        || (0 != p_i93->gre_cc_content[2] && p_i93->block_size > I93_BLEN_4BYTES)) {
        /* Rest of the block contains T5T_Area, save block data to look for NDEF TLV */
        if (!osi_memcpy_s(p_i93->t5t_cc_block, I93_BLEN_32BYTES, p_rsp->data + 1, p_i93->block_size)) {
            NFCLOG_E("osi memcpy failed %d", __LINE__);
            status = NCI_STATUS_EXT_FAILED;
            goto exit;
        }
        NFCLOG_D("need save cc block to search tlv");
        for (int i = 0; i < p_i93->block_size; i ++) {
            NFCLOG_D("cc block[%d]:0x%02x", i, p_i93->t5t_cc_block[i]);
        }
    }

    status = NCI_STATUS_OK;
exit:
    NFCLOG_D("exit");
    free_nci_buf(p_rsp);
    return status;
}


static tNCI_STATUS rw_t5t_ndef_search_tlv(void) {
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    uint16_t length = 0;
    uint8_t *p;
    tT5T_INFO *p_i93 = &s_t5t_info;
    bool search_tlv_from_cc_block = false;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);

    /* search NDEF TLV from offset 4 when CC file coded on 4 bytes
     * NFC Forum during the next block reading, if CC file is coded
     * on more than 4 bytes, start searching for NDEF TLV in the current
     * block read except if the CC
     */
    if (p_i93->gre_cc_content[2] == 0) {
        /* 8-byte CC length */
        p_i93->rw_offset = 8;
        if (p_i93->block_size > I93_BLEN_8BYTES) {
            search_tlv_from_cc_block = true;
        }
    } else {
        /* 4-byte CC length */
        p_i93->rw_offset = 4;
        if (p_i93->block_size > I93_BLEN_4BYTES) {
            search_tlv_from_cc_block = true;
        }

    }
    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
    while (true) {
        if (search_tlv_from_cc_block) {
            p = p_i93->t5t_cc_block + p_i93->rw_offset;
            length = p_i93->block_size;
            search_tlv_from_cc_block = false;
            NFCLOG_E("search tlv from cc block");
        } else {
            status = rw_i93_get_next_blocks(p_i93->rw_offset, p_rsp);
                if (status != NCI_STATUS_OK) {
                NFCLOG_E("get next block data failed");
                break;
            }
            length = p_rsp->len;
            p = p_rsp->data;
            length--;
            NFCLOG_D("length = %d", length);
            p++;
        }

        /* search TLV within read blocks */
        for (uint16_t xx = 0; xx < length; xx++) {
            NFCLOG_D("*(p + %d):0x%02x", xx, *(p + xx));
            /* if looking for type */
            if (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_TYPE) {
                if (*(p + xx) == I93_ICODE_TLV_TYPE_NDEF) {
                    /* store found type and get length field */
                    p_i93->tlv_type = *(p + xx);
                    p_i93->ndef_tlv_start_offset = p_i93->rw_offset + xx;
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_1;
                } else if (*(p + xx) == I93_ICODE_TLV_TYPE_TERM) {
                    /* no NDEF TLV found */
                    p_i93->tlv_type = I93_ICODE_TLV_TYPE_TERM;
                    break;
                } else {
                    /* TLV with Tag field set as RFU are not interpreted */
                    p_i93->tlv_type = *(p + xx);
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_1;
                }
            } else if (p_i93->tlv_detect_state ==
                        RW_I93_TLV_DETECT_STATE_LENGTH_1) {
                /* if 3 bytes length field */
                if (*(p + xx) == 0xFF) {
                    /* need 2 more bytes for length field */
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_2;
                } else {
                    p_i93->tlv_length = *(p + xx);
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_VALUE;

                    if (p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
                        p_i93->ndef_tlv_last_offset =
                            p_i93->ndef_tlv_start_offset + 1 + p_i93->tlv_length;
                        break;
                    }
                }
            } else if (p_i93->tlv_detect_state ==
                        RW_I93_TLV_DETECT_STATE_LENGTH_2) {
                /* the second byte of 3 bytes length field */
                p_i93->tlv_length = *(p + xx);
                p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_3;

            } else if (p_i93->tlv_detect_state ==
                        RW_I93_TLV_DETECT_STATE_LENGTH_3) {
                /* the last byte of 3 bytes length field */
                p_i93->tlv_length = (p_i93->tlv_length << 8) + *(p + xx);
                p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_VALUE;

                if (p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
                    p_i93->ndef_tlv_last_offset =
                        p_i93->ndef_tlv_start_offset + 3 + p_i93->tlv_length;
                    break;
                }
            } else if (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_VALUE) {
                /* this is other than NDEF TLV */
                if (p_i93->tlv_length <= length - xx) {
                    /* skip value field */
                    xx += (uint8_t)p_i93->tlv_length - 1;
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
                } else {
                    /* read more data */
                    p_i93->tlv_length -= (length - xx);
                    break;
                }
            }
        }

        /* found NDEF TLV and read length field */
        if ((p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) &&
            (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_VALUE)) {
            NFCLOG_D("t5t area last offset (%d), ndef tlv start offset(%d)",
                        p_i93->t5t_area_last_offset, p_i93->ndef_tlv_start_offset);
            p_i93->ndef_length = p_i93->tlv_length;
            p_i93->max_ndef_length =
                    p_i93->t5t_area_last_offset - p_i93->ndef_tlv_start_offset + 1;
            if (p_i93->max_ndef_length >= 0xFF) {
                /* 3 bytes length field can be used */
                p_i93->max_ndef_length -= 4;
            } else {
                /* 1 byte length field can be used */
                p_i93->max_ndef_length -= 2;
            }

            /* Complete the greedy collection */
            p_i93->gre_ndef_tlv_pos = p_i93->ndef_tlv_start_offset;
            p_i93->gre_ndef_tlv_length = p_i93->ndef_length;
            p_i93->gre_validity = 1;

            NFCLOG_D("max ndef length(%d)", p_i93->max_ndef_length);
            status = NCI_STATUS_OK;
            break;
        } else {
            /* read more data */
            p_i93->rw_offset += length;

            if (p_i93->rw_offset > p_i93->t5t_area_last_offset) {
                NFCLOG_E("can not find ndef tlv, cur offset(%d), last offset(%d)",
                            p_i93->rw_offset, p_i93->t5t_area_last_offset);
                status = NCI_STATUS_EXT_FAILED;
                break;
            } else {
                NFCLOG_D("read more data, rw offset(%d)", p_i93->rw_offset);
                reset_nci_buf(p_rsp);
                continue;
            }
        }
    }

    NFCLOG_D("exit");
    free_nci_buf(p_rsp);
    return status;
}

static tNCI_STATUS rw_i93_ndef_check_cc(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint16_t length = 0;
    uint8_t *p_rsp_data;
    uint8_t cc[4];

    NFCLOG_D("enter");

    status = rw_i93_send_cmd_read_single_block(0, false, p_rsp);
    if (status != NCI_STATUS_OK) {
        goto exit;
    }
    p_rsp_data = p_rsp->data;
    length = p_rsp->len;
    p_rsp_data++;
    length--;
    // length = length - 2;

    if (length < RW_I93_CC_SIZE) {
        NFCLOG_E("invlid cc size:%d", length);
        status = NCI_STATUS_EXT_FAILED;
        goto exit;
    }

    STREAM_TO_ARRAY(cc, p_rsp_data, RW_I93_CC_SIZE);
    /*
    ** Capability Container (CC)
    **
    ** CC[0] : magic number (0xE1)
    ** CC[1] : Bit 7-6:Major version number
    **       : Bit 5-4:Minor version number
    **       : Bit 3-2:Read access condition (00b: read access granted
    **         without any security)
    **       : Bit 1-0:Write access condition (00b: write access granted
    **         without any security)
    ** CC[2] : Memory size in 8 bytes (Ex. 0x04 is 32 bytes) [STM, ONS set
    **         to 0xFF if more than 2040bytes]
    ** CC[3] : Bit 0:Read multiple blocks is supported [NXP, STM, ONS]
    **       : Bit 1:Inventory page read is supported [NXP]
    **       : Bit 2:More than 2040 bytes are supported [STM, ONS]
    */
    NFCLOG_D("cc[0-3]: 0x%02X 0x%02X 0x%02X 0x%02X",
                cc[0], cc[1], cc[2], cc[3]);
    NFCLOG_D("Total blocks:0x%04X, Block size:0x%02X",
                p_i93->num_block, p_i93->block_size);

    status = NCI_STATUS_EXT_FAILED;
    if ((cc[0] == I93_ICODE_CC_MAGIC_NUMER_E1) ||
          (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2)) {
        if ((cc[1] & 0xC0) > I93_VERSION_1_x) {
            NFCLOG_E("Major mapping version above 1 %d.x", cc[1] >> 6);
            /* major mapping version above 1 not supported */
            status = NCI_STATUS_EXT_FAILED;
            goto exit;
        }
        if ((cc[1] & I93_ICODE_CC_READ_ACCESS_MASK) ==
            I93_ICODE_CC_READ_ACCESS_GRANTED) {
            if ((cc[1] & I93_ICODE_CC_WRITE_ACCESS_MASK) !=
                I93_ICODE_CC_WRITE_ACCESS_GRANTED) {
                /* read-only or password required to write */
                p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
            }
            if (cc[3] & I93_ICODE_CC_MBREAD_MASK) {
                /* tag supports read multiple blocks command */
                p_i93->intl_flags |= RW_I93_FLAG_READ_MULTI_BLOCK;
            }
            if (cc[3] & I93_ICODE_CC_SPECIAL_FRAME_MASK) {
                /* tag supports Special Frame for Write-Alike commands */
                p_i93->intl_flags |= RW_I93_FLAG_SPECIAL_FRAME;
            }
            if (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2) {
                p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
            }
            status = NCI_STATUS_OK;
        }
    }

    if (NCI_STATUS_OK == status) {
        /* seach NDEF TLV from offset 4 when CC file coded on 4 bytes NFC Forum
        */
        if (cc[2] != 0)
            p_i93->cc_size = RW_I93_CC_SIZE;
        else
            p_i93->cc_size = RW_I93_CC_SIZE_8;
    }
exit:
    NFCLOG_D("exit");
    free_nci_buf(p_rsp);
    return status;
}

static tNCI_STATUS rw_i93_ndef_check_lock_status(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0;
    uint32_t block = 0, first_block, last_block = 0, num_blocks;

    NFCLOG_D("enter");

    /* get lock status to see if read-only */
    if ((p_i93->product_version == RW_I93_TAG_IT_HF_I_STD_CHIP_INLAY) ||
        (p_i93->product_version == RW_I93_TAG_IT_HF_I_PRO_CHIP_INLAY) ||
        ((p_i93->uid[I93_UID_MFG_CODE_IND] == I93_UID_IC_MFG_CODE_NXP) &&
        (p_i93->ic_reference & I93_ICODE_IC_REF_MBREAD_MASK))) {
        /* these doesn't support GetMultiBlockSecurityStatus */
        NFCLOG_D("check lock status by reading single block");

        p_i93->rw_offset = p_i93->ndef_tlv_start_offset;

        while (true) {
            /* read block to get lock status */
            status = rw_i93_send_cmd_read_single_block( (uint32_t)(p_i93->rw_offset / p_i93->block_size) , true, p_rsp);
            if (status != NCI_STATUS_OK) {
                NFCLOG_E("read single block failed");
                break;
            }
            length = p_rsp->len;
            p_rsp_data = p_rsp->data;
            length --;
            p_rsp_data++;

            block = (p_i93->rw_offset / p_i93->block_size);
            last_block = (p_i93->ndef_tlv_last_offset / p_i93->block_size);

            if ((*p_rsp_data) & I93_BLOCK_LOCKED) {
                if (block <= last_block) {
                    p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
                }
                NFCLOG_I("block(%d) locked, last block(%d)", block, last_block);
                break;
            } else {
                /* if we need to check more user blocks */
                if (block + 1 < p_i93->num_block) {
                    p_i93->rw_offset += p_i93->block_size;
                    /* read block to get lock status */
                    NFCLOG_D("read next single block, offset:(%d)", p_i93->rw_offset);
                    reset_nci_buf(p_rsp);
                    continue;
                } else {
                    NFCLOG_I("read all blocks done");
                    break;
                }
            }

        }

        p_i93->max_ndef_length = p_i93->ndef_length
            /* add available bytes including the last block of NDEF TLV */
            + (p_i93->block_size * (block - last_block) + 1) -
            (p_i93->ndef_tlv_last_offset % p_i93->block_size) - 1;
        NFCLOG_I("max_ndef_length:%d", p_i93->max_ndef_length);

    } else {
        NFCLOG_D("check lock status by reading multi blocks");
        /* block offset for read-only check */
        p_i93->rw_offset = 0;
        while(true) {
            status = rw_i93_get_next_block_sec(p_rsp);
            if (status != NCI_STATUS_OK) {
                NFCLOG_E("read next block security status failed");
                break;
            }
            length = p_rsp->len;
            p_rsp_data = p_rsp->data;
            length --;
            p_rsp_data++;
            if (p_i93->rw_offset == 0) {
                p_i93->max_ndef_length =
                    p_i93->ndef_length
                    /* add available bytes in the last block of NDEF TLV */
                    + p_i93->block_size -
                    (p_i93->ndef_tlv_last_offset % p_i93->block_size) - 1;

                first_block = (p_i93->ndef_tlv_start_offset / p_i93->block_size);
            } else {
                first_block = 0;
            }

            last_block = (p_i93->ndef_tlv_last_offset / p_i93->block_size);
            num_blocks = length;

            for (block = first_block; block < num_blocks; block++) {
                /* if any block of NDEF TLV is locked */
                if ((block + p_i93->rw_offset) <= last_block) {
                    if (*(p_rsp_data + block) & I93_BLOCK_LOCKED) {
                        p_i93->intl_flags |= RW_I93_FLAG_READ_ONLY;
                        break;
                    }
                } else {
                    if (*(p_rsp_data + block) & I93_BLOCK_LOCKED) {
                        /* no more consecutive unlocked block */
                        break;
                    } else {
                        /* add block size if not locked */
                        p_i93->max_ndef_length += p_i93->block_size;
                    }
                }
            }

            /* update next security of block to check */
            p_i93->rw_offset += num_blocks;

            /* if need to check more */
            if (p_i93->num_block > p_i93->rw_offset) {
                NFCLOG_D("read next security status, offset:%d)", p_i93->rw_offset);
                reset_nci_buf(p_rsp);
                continue;
            } else {
                NFCLOG_I("read all blocks security status done");
                break;

            }

        }
    }

    /* check if need to adjust max NDEF length */
    if ((p_i93->ndef_length < 0xFF) && (p_i93->max_ndef_length >= 0xFF)) {
        /* 3 bytes length field must be used */
        p_i93->max_ndef_length -= 2;
    }

    NFCLOG_D("exit");
    free_nci_buf(p_rsp);
    return status;

}

static tNCI_STATUS rw_i93_ndef_search_tlv(void) {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0;

    NFCLOG_D("enter");
    if( (p_i93->cc_size != RW_I93_CC_SIZE) && (p_i93->cc_size != RW_I93_CC_SIZE_8)) {
        NFCLOG_E("invalid cc size:%d", p_i93->cc_size);
        return NCI_STATUS_EXT_FAILED;
    }
    p_i93->rw_offset = p_i93->cc_size;
    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;

    while (true) {
        status = rw_i93_get_next_blocks(p_i93->rw_offset, p_rsp);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("get next block data failed");
            break;
        }
        length = p_rsp->len;
        p_rsp_data = p_rsp->data;
        length--;
        NFCLOG_D("length = %d", length);
        p_rsp_data++;
         /* search TLV within read blocks */
        for (uint16_t xx = 0; xx < length; xx++) {
            NFCLOG_D("*(p_rsp_data + %d):0x%02x", xx, *(p_rsp_data + xx));
            /* if looking for type */
            if (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_TYPE) {
                if (*(p_rsp_data + xx) == I93_ICODE_TLV_TYPE_NULL) {
                    continue;
                } else if ((*(p_rsp_data + xx) == I93_ICODE_TLV_TYPE_NDEF) ||
                        (*(p_rsp_data + xx) == I93_ICODE_TLV_TYPE_PROP)) {
                    /* store found type and get length field */
                    p_i93->tlv_type = *(p_rsp_data + xx);
                    p_i93->ndef_tlv_start_offset = p_i93->rw_offset + xx;
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_1;
                } else if (*(p_rsp_data + xx) == I93_ICODE_TLV_TYPE_TERM) {
                    /* no NDEF TLV found */
                    p_i93->tlv_type = I93_ICODE_TLV_TYPE_TERM;
                    break;
                } else {
                    /*invalid tlv type, exit*/
                    p_i93->tlv_type = *(p_rsp_data + xx);
                    break;
                }
            } else if (p_i93->tlv_detect_state ==
                        RW_I93_TLV_DETECT_STATE_LENGTH_1) {
                /* if 3 bytes length field */
                if (*(p_rsp_data + xx) == 0xFF) {
                    /* need 2 more bytes for length field */
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_2;
                } else {
                    p_i93->tlv_length = *(p_rsp_data + xx);
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_VALUE;

                    if (p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
                            p_i93->ndef_tlv_last_offset =
                            p_i93->ndef_tlv_start_offset + 1 + p_i93->tlv_length;
                        break;
                    }
                }
            } else if (p_i93->tlv_detect_state ==
                        RW_I93_TLV_DETECT_STATE_LENGTH_2) {
                /* the second byte of 3 bytes length field */
                p_i93->tlv_length = *(p_rsp_data + xx);
                p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_LENGTH_3;
            } else if (p_i93->tlv_detect_state ==
                        RW_I93_TLV_DETECT_STATE_LENGTH_3) {
                /* the last byte of 3 bytes length field */
                p_i93->tlv_length = (p_i93->tlv_length << 8) + *(p_rsp_data + xx);
                p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_VALUE;

                if (p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
                    p_i93->ndef_tlv_last_offset =
                    p_i93->ndef_tlv_start_offset + 3 + p_i93->tlv_length;
                    break;
                }
            } else if (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_VALUE) {
                /* this is other than NDEF TLV */
                if (p_i93->tlv_length <= length - xx) {
                    /* skip value field */
                    xx += (uint8_t)p_i93->tlv_length;
                    p_i93->tlv_detect_state = RW_I93_TLV_DETECT_STATE_TYPE;
                } else {
                    /* read more data */
                    p_i93->tlv_length -= (length - xx);
                    break;
                }
            }
        }

        /* found NDEF TLV and read length field */
        if ((p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) &&
            (p_i93->tlv_detect_state == RW_I93_TLV_DETECT_STATE_VALUE)) {

            p_i93->ndef_length = p_i93->tlv_length;
            status = NCI_STATUS_OK;
            break;

        } else if (p_i93->tlv_type != I93_ICODE_TLV_TYPE_NULL
                && p_i93->tlv_type != I93_ICODE_TLV_TYPE_NDEF
                && p_i93->tlv_type != I93_ICODE_TLV_TYPE_PROP
                && p_i93->tlv_type != I93_ICODE_TLV_TYPE_TERM) {
            /* invlid tlv type */
            NFCLOG_E("invalid tlv type: 0x%02x", p_i93->tlv_type);
            status = NCI_STATUS_EXT_FAILED;
            break;
        } else {
            /* read more data */
            p_i93->rw_offset += length;
            NFCLOG_D("rw_offset:%d", p_i93->rw_offset);
            if (p_i93->rw_offset >= p_i93->block_size * p_i93->num_block) {
                NFCLOG_E("rw_offset exceed limit");
                status = NCI_STATUS_EXT_FAILED;
                break;
            }
            reset_nci_buf(p_rsp);
        }
    }

    NFCLOG_D("exit");
    free_nci_buf(p_rsp);
    return status;
}

static tNCI_STATUS rw_t5t_ndef_reset_tlv_block() {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0, xx = 0;
    uint32_t length_offset = 0, block_number = 0;

    NFCLOG_D("enter");
    /* read length field */
    p_i93->rw_offset = p_i93->ndef_tlv_start_offset + 1;
    p_i93->rw_length = 0;

    block_number = p_i93->rw_offset / p_i93->block_size;

    status = rw_i93_send_cmd_read_single_block(block_number, false, p_rsp);
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("read single block failed");
        goto exit;
    }
    length = p_rsp->len;
    p_rsp_data = p_rsp->data;
    length --;
    p_rsp_data++;

    /* get offset of length field */
    length_offset = (p_i93->ndef_tlv_start_offset + 1) % p_i93->block_size;
    if (length < length_offset) {
        NFCLOG_E("invlid length (%d), length offset(%d)", length, length_offset);
        status = NCI_STATUS_EXT_FAILED;
      goto exit;
    }
    /* set length to zero */
    *(p_rsp_data + length_offset) = 0x00;

    if (p_i93->ndef_length > 0) {
        /* if 3 bytes length field is needed */
        if (p_i93->ndef_length >= 0xFF) {
            xx = length_offset + 3;
        } else {
            xx = length_offset + 1;
        }
        if (p_i93->ndef_length >= 0xFF) {
          p_i93->ndef_tlv_last_offset = p_i93->ndef_tlv_start_offset + 3;
        } else {
          p_i93->ndef_tlv_last_offset = p_i93->ndef_tlv_start_offset + 1;
        }
        /* write the first part of NDEF in the same block */
        for (; xx < p_i93->block_size; xx++) {
            if (xx > length || p_i93->rw_length > p_i93->ndef_length) {
                status = NCI_STATUS_EXT_FAILED;
                NFCLOG_E("invalide xx(%d), rw length(%d), ndef length(%d)",
                            xx, p_i93->rw_length, p_i93->ndef_length);
                goto exit;
            }
            if (p_i93->rw_length < p_i93->ndef_length) {
                *(p_rsp_data + xx) = *(p_i93->p_update_data + p_i93->rw_length++);
                p_i93->ndef_tlv_last_offset++;
            } else {
                *(p_rsp_data + xx) = I93_ICODE_TLV_TYPE_NULL;
            }
        }
    }
    block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
    // if (length < p_i93->block_size) {
    //     status = NCI_STATUS_EXT_FAILED;
    //     NFCLOG_E("invalide length(%d), block size(%d)", length, p_i93->block_size);
    //     goto exit;
    // }
    status = rw_i93_send_cmd_write_single_block(block_number, p_rsp_data);
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("wirte single block failed");
        goto exit;
    }
exit:
    NFCLOG_D("exit");
    free_nci_buf(p_rsp);
    return status;
}
static tNCI_STATUS rw_t5t_ndef_write_blocks() {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    uint8_t *p;
    uint16_t xx = 0;
    uint32_t block_number = 0;
    uint8_t buff[I93_MAX_BLOCK_LENGH];

    NFCLOG_D("enter");
    block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
    /* update next writing offset */
    p_i93->rw_offset = (block_number + 1) * p_i93->block_size;

    do {
        /* if it's not the end of tag memory */
        if (p_i93->rw_offset <= p_i93->t5t_area_last_offset) {
            // Note: Needed to write in the last block of the memory
            block_number = p_i93->rw_offset / p_i93->block_size;
            /* if we have more data to write */
            if (p_i93->rw_length < p_i93->ndef_length) {
                p = p_i93->p_update_data + p_i93->rw_length;
                p_i93->rw_offset += p_i93->block_size;
                p_i93->rw_length += p_i93->block_size;
                /* if this is the last block of NDEF TLV */
                if (p_i93->rw_length >= p_i93->ndef_length) {
                    /* length of NDEF TLV in the block */
                    xx = (uint8_t)(p_i93->block_size -
                                    (p_i93->rw_length - p_i93->ndef_length));
                    /* set NULL TLV in the unused part of block */
                    if (!osi_memset_s(buff, I93_MAX_BLOCK_LENGH, I93_ICODE_TLV_TYPE_NULL, p_i93->block_size)) {
                        NFCLOG_E("osi memset failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        break;
                    }
                    if (!osi_memcpy_s(buff, I93_MAX_BLOCK_LENGH, p, xx)) {
                        NFCLOG_E("osi memcpy failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        break;
                    }
                    p = buff;
                    /* if it's the end of tag memory */
                    if (((p_i93->rw_offset - p_i93->block_size + xx) <=
                        p_i93->t5t_area_last_offset) &&
                        (xx < p_i93->block_size)) {
                        buff[xx] = I93_ICODE_TLV_TYPE_TERM;
                    }
                    // Note: Needed to write Terminator TLV in block following
                    // the NDEF Message ending in byte 3 of the previous blo
                    p_i93->ndef_tlv_last_offset = p_i93->rw_offset - p_i93->block_size + xx - 1;
                } else {
                    p_i93->ndef_tlv_last_offset += p_i93->block_size;
                }
                status = rw_i93_send_cmd_write_single_block(block_number, p);
                if (status != NCI_STATUS_OK){
                    NFCLOG_E("write ndef block failed");
                    break;
                }
                /* continue write ndef block*/
                continue;
            } else {
                /* if this is the very next block of NDEF TLV */
                // Note: Needed to write Terminator TLV in block following
                // the NDEF Message ending in byte 3 of the previous block
                if ((block_number ==
                    (p_i93->ndef_tlv_last_offset / p_i93->block_size) + 1) &&
                    (((p_i93->ndef_tlv_last_offset + 1) % p_i93->block_size) == 0)) {
                    /* write Terminator TLV and NULL TLV */
                    NFCLOG_I("write ndef terminator tlv, block number(%d)", block_number);
                    if (!osi_memset_s(buff, I93_MAX_BLOCK_LENGH, I93_ICODE_TLV_TYPE_NULL, p_i93->block_size)) {
                        NFCLOG_E("osi memset failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        break;
                    }
                    buff[0] = I93_ICODE_TLV_TYPE_TERM;
                    p = buff;
                    status = rw_i93_send_cmd_write_single_block(block_number, p);
                    if (status != NCI_STATUS_OK){
                        NFCLOG_E("write ndef terminate block failed");
                        break;
                    }

                    break;
                } else {
                    /* finished writing NDEF and Terminator TLV */
                    status = NCI_STATUS_OK;
                    break;
                }
            }
        } else {
            /* if we have no more data to write */
            if (p_i93->rw_length >= p_i93->ndef_length) {
                /* finished writing NDEF and Terminator TLV */
                status = NCI_STATUS_OK;
                break;
            }
            status = NCI_STATUS_EXT_FAILED;
            break;
        }
    } while (true);

    NFCLOG_D("exit");
    return status;
}
static tNCI_STATUS rw_t5t_ndef_update_length() {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0, xx = 0;
    uint32_t length_offset = 0, block_number = 0;

    /* set offset to length field */
    p_i93->rw_offset = p_i93->ndef_tlv_start_offset + 1;
    /* get size of length field */
    if (p_i93->ndef_length >= 0xFF) {
        p_i93->rw_length = 3;
    } else if (p_i93->ndef_length > 0) {
        p_i93->rw_length = 1;
    } else {
        p_i93->rw_length = 0;
    }

    /* read length field to update length       */
    block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;

    while (p_i93->rw_length > 0) {
        status = rw_i93_send_cmd_read_single_block(block_number, false, p_rsp);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("read single block failed");
            goto exit;
        }

        length = p_rsp->len;
        p_rsp_data = p_rsp->data;
        length --;
        p_rsp_data++;

        length_offset = p_i93->rw_offset % p_i93->block_size;
        /* update length field within the read block */
        for (xx = length_offset; xx < p_i93->block_size; xx++) {
            if (xx > length) {
                status = NCI_STATUS_EXT_FAILED;
                NFCLOG_E("invalid xx(%d), length(%d)", xx, length);
                goto exit;
            }

            if (p_i93->rw_length == 3)
                *(p_rsp_data + xx) = 0xFF;
            else if (p_i93->rw_length == 2)
                *(p_rsp_data + xx) = (uint8_t)((p_i93->ndef_length >> 8) & 0xFF);
            else if (p_i93->rw_length == 1)
                *(p_rsp_data + xx) = (uint8_t)(p_i93->ndef_length & 0xFF);

            p_i93->rw_length--;
            if (p_i93->rw_length == 0) {
                NFCLOG_I("update length field within the read block done");
                break;
            }

        }
        block_number = (p_i93->rw_offset / p_i93->block_size);

        // if (length < p_i93->block_size) {
        //     status = NCI_STATUS_EXT_FAILED;
        //     NFCLOG_E("invalid length(%d), block size(%d)", length, p_i93->block_size);
        //     goto exit;
        // }
        status = rw_i93_send_cmd_write_single_block(block_number, p_rsp_data);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("wirte single block(%d)failed", block_number);
            goto exit;
        }
        p_i93->rw_offset +=
                p_i93->block_size - (p_i93->rw_offset % p_i93->block_size);

        block_number = p_i93->rw_offset / p_i93->block_size;
        reset_nci_buf(p_rsp);
    }

    NFCLOG_I("NDEF update complete, %d bytes, (%d-%d)",
            p_i93->ndef_length,
            p_i93->ndef_tlv_start_offset,
            p_i93->ndef_tlv_last_offset);

    status = NCI_STATUS_OK;

exit:
    free_nci_buf(p_rsp);
    return status;
}
static tNCI_STATUS rw_i93_ndef_write_blocks() {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    uint8_t *p;
    uint16_t xx = 0;
    uint32_t block_number = 0;
    uint8_t buff[I93_MAX_BLOCK_LENGH];

    NFCLOG_D("enter");
    block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
    /* update next writing offset */
    p_i93->rw_offset = (block_number + 1) * p_i93->block_size;

    do {
        /* if it's not the end of tag memory */
        if (p_i93->rw_offset < p_i93->block_size * p_i93->num_block) {
            block_number = p_i93->rw_offset / p_i93->block_size;
            /* if we have more data to write */
            if (p_i93->rw_length < p_i93->ndef_length) {
                p = p_i93->p_update_data + p_i93->rw_length;
                p_i93->rw_offset += p_i93->block_size;
                p_i93->rw_length += p_i93->block_size;
                /* if this is the last block of NDEF TLV */
                if (p_i93->rw_length > p_i93->ndef_length) {
                    /* length of NDEF TLV in the block */
                    xx = (uint8_t)(p_i93->block_size -
                                    (p_i93->rw_length - p_i93->ndef_length));
                    /* set NULL TLV in the unused part of block */
                    if (!osi_memset_s(buff, I93_MAX_BLOCK_LENGH, I93_ICODE_TLV_TYPE_NULL, p_i93->block_size)) {
                        NFCLOG_E("osi memset failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        break;
                    }
                    if (!osi_memcpy_s(buff, I93_MAX_BLOCK_LENGH, p, xx)) {
                        NFCLOG_E("osi memcpy failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        break;
                    }
                    p = buff;
                    /* if it's the end of tag memory */
                    if ((p_i93->rw_offset >= p_i93->block_size * p_i93->num_block) &&
                        (xx < p_i93->block_size)) {
                        buff[xx] = I93_ICODE_TLV_TYPE_TERM;
                    }
                    p_i93->ndef_tlv_last_offset = p_i93->rw_offset - p_i93->block_size + xx - 1;
                }
                status = rw_i93_send_cmd_write_single_block(block_number, p);
                if (status != NCI_STATUS_OK){
                    NFCLOG_E("write ndef block failed");
                    break;
                }
                /* continue write ndef block*/
                continue;
            } else {
                /* if this is the very next block of NDEF TLV */
                if (block_number ==
                    (p_i93->ndef_tlv_last_offset / p_i93->block_size) + 1) {
                    p_i93->rw_offset += p_i93->block_size;
                    /* write Terminator TLV and NULL TLV */
                    if (!osi_memset_s(buff, I93_MAX_BLOCK_LENGH, I93_ICODE_TLV_TYPE_NULL, p_i93->block_size)) {
                        NFCLOG_E("osi memset failed %d", __LINE__);
                        status = NCI_STATUS_EXT_FAILED;
                        break;
                    }
                    buff[0] = I93_ICODE_TLV_TYPE_TERM;
                    p = buff;
                    status = rw_i93_send_cmd_write_single_block(block_number, p);
                    if (status != NCI_STATUS_OK){
                        NFCLOG_E("write ndef terminate block failed");
                        break;
                    }
                } else {
                    /* finished writing NDEF and Terminator TLV */
                    status = NCI_STATUS_OK;
                    break;
                }
            }
        } else {
            /* if we have no more data to write */
            if (p_i93->rw_length >= p_i93->ndef_length) {
                /* finished writing NDEF and Terminator TLV */
                status = NCI_STATUS_OK;
                break;
            }
            status = NCI_STATUS_EXT_FAILED;
            break;
        }
    } while (true);

    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS rw_i93_ndef_update_length() {
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0, xx = 0;
    uint32_t length_offset = 0, block_number = 0;

    /* set offset to length field */
    p_i93->rw_offset = p_i93->ndef_tlv_start_offset + 1;
    /* get size of length field */
    if (p_i93->ndef_length >= 0xFF) {
        p_i93->rw_length = 3;
    } else if (p_i93->ndef_length > 0) {
        p_i93->rw_length = 1;
    } else {
        p_i93->rw_length = 0;
    }

    /* read length field to update length       */
    block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;

    while (p_i93->rw_length > 0) {
        status = rw_i93_send_cmd_read_single_block(block_number, false, p_rsp);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("read single block failed");
            goto exit;
        }

        length = p_rsp->len;
        p_rsp_data = p_rsp->data;
        length --;
        p_rsp_data++;

        length_offset = p_i93->rw_offset % p_i93->block_size;
        /* update length field within the read block */
        for (xx = length_offset; xx < p_i93->block_size; xx++) {
            if (xx > length) {
                status = NCI_STATUS_EXT_FAILED;
                NFCLOG_E("invalid xx(%d), length(%d)", xx, length);
                goto exit;
            }

            if (p_i93->rw_length == 3)
                *(p_rsp_data + xx) = 0xFF;
            else if (p_i93->rw_length == 2)
                *(p_rsp_data + xx) = (uint8_t)((p_i93->ndef_length >> 8) & 0xFF);
            else if (p_i93->rw_length == 1)
                *(p_rsp_data + xx) = (uint8_t)(p_i93->ndef_length & 0xFF);

            p_i93->rw_length--;
            if (p_i93->rw_length == 0) {
                NFCLOG_I("update length field within the read block done");
                break;
            }

        }
        block_number = (p_i93->rw_offset / p_i93->block_size);

        if (length < p_i93->block_size) {
            status = NCI_STATUS_EXT_FAILED;
            NFCLOG_E("invalid length(%d), block size(%d)", length, p_i93->block_size);
            goto exit;
        }
        status = rw_i93_send_cmd_write_single_block(block_number, p_rsp_data);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("wirte single block(%d)failed", block_number);
            goto exit;
        }
        p_i93->rw_offset +=
                p_i93->block_size - (p_i93->rw_offset % p_i93->block_size);

        block_number = p_i93->rw_offset / p_i93->block_size;
        reset_nci_buf(p_rsp);
    }

    NFCLOG_I("NDEF update complete, %d bytes, (%d-%d)",
            p_i93->ndef_length,
            p_i93->ndef_tlv_start_offset,
            p_i93->ndef_tlv_last_offset);

    status = NCI_STATUS_OK;

exit:
    free_nci_buf(p_rsp);
    return status;
}

static tNCI_STATUS rw_i93_ndef_reset_tlv_block() {

    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0, xx = 0;
    uint32_t length_offset = 0, block_number = 0;

    NFCLOG_D("enter");
    /* read length field */
    p_i93->rw_offset = p_i93->ndef_tlv_start_offset + 1;
    p_i93->rw_length = 0;

    block_number = p_i93->rw_offset / p_i93->block_size;

    status = rw_i93_send_cmd_read_single_block(block_number, false, p_rsp);
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("read single block failed");
        goto exit;
    }
    length = p_rsp->len;
    p_rsp_data = p_rsp->data;
    length --;
    p_rsp_data++;

    /* get offset of length field */
    length_offset = (p_i93->ndef_tlv_start_offset + 1) % p_i93->block_size;
    if (length < length_offset) {
        NFCLOG_E("invlid length (%d), length offset(%d)", length, length_offset);
        status = NCI_STATUS_EXT_FAILED;
      goto exit;
    }
    /* set length to zero */
    *(p_rsp_data + length_offset) = 0x00;

    if (p_i93->ndef_length > 0) {
        /* if 3 bytes length field is needed */
        if (p_i93->ndef_length >= 0xFF) {
            xx = length_offset + 3;
        } else {
            xx = length_offset + 1;
        }
        /* write the first part of NDEF in the same block */
        for (; xx < p_i93->block_size; xx++) {
            if (xx > length || p_i93->rw_length > p_i93->ndef_length) {
                status = NCI_STATUS_EXT_FAILED;
                NFCLOG_E("invalide xx(%d), rw length(%d), ndef length(%d)",
                            xx, p_i93->rw_length, p_i93->ndef_length);
                goto exit;
            }
            if (p_i93->rw_length < p_i93->ndef_length) {
                *(p_rsp_data + xx) = *(p_i93->p_update_data + p_i93->rw_length++);
            } else {
                *(p_rsp_data + xx) = I93_ICODE_TLV_TYPE_NULL;
            }
        }
    }
    block_number = (p_i93->ndef_tlv_start_offset + 1) / p_i93->block_size;
    if (length < p_i93->block_size) {
        status = NCI_STATUS_EXT_FAILED;
        NFCLOG_E("invalide length(%d), block size(%d)", length, p_i93->block_size);
        goto exit;
    }
    status = rw_i93_send_cmd_write_single_block(block_number, p_rsp_data);
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("wirte single block failed");
        goto exit;
    }
exit:
    NFCLOG_D("exit");
    free_nci_buf(p_rsp);
    return status;
}

static tNCI_STATUS rw_i93_write_cc_ndef_tlv() {

    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    uint8_t *p;
    uint32_t block_number = 0;

    /* get buffer to store CC, zero length NDEF TLV and Terminator TLV */
    /* Block size could be either 4 or 8 or 16 or 32 bytes */
    /* Get buffer for the largest block size I93_MAX_BLOCK_LENGH */
    p_i93->p_update_data = (uint8_t*)osi_calloc(I93_MAX_BLOCK_LENGH);
    if (!p_i93->p_update_data) {
        status = NCI_STATUS_EXT_ALLOC_FAILED;
        goto exit;
    } else {
        switch (p_i93->block_size) {
            case 4:
            case 8:
                break;
            case 16:
            case 32: /* initialize unpopulated buffer b/139738828 */
                if (!osi_memset_s(p_i93->p_update_data, I93_MAX_BLOCK_LENGH, I93_ICODE_TLV_TYPE_NULL, I93_MAX_BLOCK_LENGH)) {
                    NFCLOG_E("osi memset failed %d", __LINE__);
                    status = NCI_STATUS_EXT_FAILED;
                    goto exit;
                }
                break;
            default:
                 NFCLOG_E("invalid block size(%d)", p_i93->block_size);
                status = NCI_STATUS_EXT_FAILED;
                goto exit;
        }
    }
    p = p_i93->p_update_data;
    /* Capability Container */
    *(p++) = I93_ICODE_CC_MAGIC_NUMER_E1; /* magic number */
    *(p++) = 0x40;                        /* version 1.0, read/write */
    /* if memory size is less than 2048 bytes */
    if (((p_i93->num_block * p_i93->block_size) / 8) < 0x100)
        *(p++) = (uint8_t)((p_i93->num_block * p_i93->block_size) /
                         8); /* memory size */
    else
        *(p++) = 0xFF;
    if ((p_i93->product_version == RW_I93_ICODE_SLI) ||
        (p_i93->product_version == RW_I93_ICODE_SLI_S) ||
        (p_i93->product_version == RW_I93_ICODE_SLI_L)) {
        if (p_i93->ic_reference & I93_ICODE_IC_REF_MBREAD_MASK)
            *(p++) = I93_ICODE_CC_IPREAD_MASK; /* IPREAD */
        else
            *(p++) = I93_ICODE_CC_MBREAD_MASK; /* MBREAD, read multi block command
                                                supported */
    } else if ((p_i93->product_version == RW_I93_TAG_IT_HF_I_PLUS_INLAY) ||
               (p_i93->product_version == RW_I93_TAG_IT_HF_I_PLUS_CHIP)) {
        *(p++) = I93_ICODE_CC_MBREAD_MASK; /* MBREAD, read multi block command
                                                supported */
    } else if ((p_i93->product_version ==
                RW_I93_TAG_IT_HF_I_STD_CHIP_INLAY) ||
               (p_i93->product_version ==
                RW_I93_TAG_IT_HF_I_PRO_CHIP_INLAY)) {
        *(p++) = 0;
    } else {
        /* ST except LRIS2K, ONS, Broadcom supports read multi block command */
        /* if memory size is more than 2040 bytes (which is not LRIS2K) */
        if (((p_i93->num_block * p_i93->block_size) / 8) > 0xFF)
            *(p++) = (I93_ICODE_CC_MBREAD_MASK | I93_ST_CC_OVERFLOW_MASK);
        else if (p_i93->product_version == RW_I93_ST_LRIS2K)
            *(p++) = 0x00;
        else
            *(p++) = I93_ICODE_CC_MBREAD_MASK;
    }
    /* zero length NDEF and Terminator TLV */
    *(p++) = I93_ICODE_TLV_TYPE_NDEF;
    *(p++) = 0x00;
    *(p++) = I93_ICODE_TLV_TYPE_TERM;
    *(p++) = I93_ICODE_TLV_TYPE_NULL;
    /* start from block 0 */
    p_i93->rw_offset = 0;

    while(p_i93->rw_offset < RW_I93_FORMAT_DATA_LEN) {
        block_number = (p_i93->rw_offset / p_i93->block_size);
        p = p_i93->p_update_data + p_i93->rw_offset;
        status = rw_i93_send_cmd_write_single_block(block_number, p);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("wirte single block failed");
            goto exit;
        } else {
            p_i93->rw_offset += p_i93->block_size;
        }

    }
    status = NCI_STATUS_OK;
exit:
    NFCLOG_D("exit");
    if (p_i93->p_update_data) {
        osi_free(p_i93->p_update_data);
        p_i93->p_update_data = NULL;
    }
    return status;

}

static tNCI_STATUS rw_i93_check_ndef_writable(void){

    tNCI_STATUS status = NCI_STATUS_EXT_NOT_SUPPORTED;
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0, xx = 0;

    NFCLOG_D("enter");
    /* get lock status to see if read-only */
    if ((p_i93->product_version == RW_I93_TAG_IT_HF_I_STD_CHIP_INLAY) ||
        (p_i93->product_version == RW_I93_TAG_IT_HF_I_PRO_CHIP_INLAY) ||
        ((p_i93->uid[I93_UID_MFG_CODE_IND] == I93_UID_IC_MFG_CODE_NXP) &&
        (p_i93->ic_reference & I93_ICODE_IC_REF_MBREAD_MASK))) {
        /* these doesn't support GetMultiBlockSecurityStatus */
        NFCLOG_D("check ndef writable by reading single block");
        p_i93->rw_offset = 0;
        while(true) {
            /* read block to get lock status */
            status = rw_i93_send_cmd_read_single_block( (uint32_t)(p_i93->rw_offset / p_i93->block_size) , true, p_rsp);
            if (status != NCI_STATUS_OK) {
                NFCLOG_E("read single block failed");
                break;
            }
            length = p_rsp->len;
            p_rsp_data = p_rsp->data;
            length --;
            p_rsp_data++;
            if ((*p_rsp_data) & I93_BLOCK_LOCKED) {
                NFCLOG_E("current block locked, rw offset(%d), block size(%d)", p_i93->rw_offset, p_i93->block_size);
                status = NCI_STATUS_EXT_NOT_SUPPORTED;
                break;
            }

            /* if we checked all of user blocks */
            if ((p_i93->rw_offset / p_i93->block_size) + 1 == p_i93->num_block) {
                if ((p_i93->product_version == RW_I93_TAG_IT_HF_I_STD_CHIP_INLAY) ||
                    (p_i93->product_version == RW_I93_TAG_IT_HF_I_PRO_CHIP_INLAY)) {
                    /* read the block which has AFI */
                    p_i93->rw_offset = I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_AFI_LOCATION;
                    reset_nci_buf(p_rsp);
                    continue;
                }
            } else if (p_i93->rw_offset == I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_AFI_LOCATION) {
                /* no block is locked */
                status = NCI_STATUS_OK;
                break;
            } else {
                p_i93->rw_offset += p_i93->block_size;
                reset_nci_buf(p_rsp);
                continue;
            }
        }
    } else {
        NFCLOG_D("check ndef writable by reading multi blocks");
        /* block offset for read-only check */
        p_i93->rw_offset = 0;
        while(true) {
            status = rw_i93_get_next_block_sec(p_rsp);
            if (status != NCI_STATUS_OK) {
                NFCLOG_E("read next block security status failed");
                break;
            }
            length = p_rsp->len;
            p_rsp_data = p_rsp->data;
            length --;
            p_rsp_data++;
            /* if any block is locked, we cannot format it */
            for (xx = 0; xx < length; xx++) {
                if (*(p_rsp_data + xx) & I93_BLOCK_LOCKED) {
                    NFCLOG_E("current block locked, rw offset(%d), block size(%d)", p_i93->rw_offset, p_i93->block_size);
                    status = NCI_STATUS_EXT_NOT_SUPPORTED;
                    break;
                }
            }

            /* update block offset for read-only check */
            p_i93->rw_offset += length;

            /* if need to get more lock status of blocks */
            if (p_i93->num_block > p_i93->rw_offset) {
                reset_nci_buf(p_rsp);
                continue;
            } else {
                status = NCI_STATUS_OK;
                break;
            }
        }
    }


    free_nci_buf(p_rsp);
    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS is_ndef_formatable(){
    return NCI_STATUS_OK;
}

static tNCI_STATUS ndef_format() {
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tT5T_INFO *p_i93 = &s_t5t_info;
    NFCLOG_D("enter");



    if (!((p_i93->product_version == RW_I93_TAG_IT_HF_I_STD_CHIP_INLAY) ||
        (p_i93->product_version == RW_I93_TAG_IT_HF_I_PRO_CHIP_INLAY))) {
        /* These don't support GetSystemInformation and GetMultiBlockSecurityStatus */
        status = rw_i93_get_sys_info(p_i93->uid);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("get system info failed");
            return status;
        }
        if ((p_i93->block_size == 0) || (p_i93->num_block == 0)) {
            NFCLOG_E("invalid block size or number block");
            return status;
        }
        if (p_i93->info_flags & I93_INFO_FLAG_DSFID) {
            /* DSFID, if any DSFID then reset */
            if (p_i93->dsfid != I93_DFS_UNSUPPORTED) {
                // p_i93->intl_flags |= RW_I93_FLAG_RESET_DSFID;
                status = rw_i93_send_cmd_write_dsfid(I93_DFS_UNSUPPORTED);
                if (status != NCI_STATUS_OK) {
                    NFCLOG_E("write dfs failed");
                    return status;
                }
            }
        }
        if (p_i93->info_flags & I93_INFO_FLAG_AFI) {
            /* AFI, reset to 0 */
            if (p_i93->afi != 0x00) {
                // p_i93->intl_flags |= RW_I93_FLAG_RESET_AFI;
                status = rw_i93_send_cmd_write_afi(0x00);
                if (status != NCI_STATUS_OK) {
                    NFCLOG_E("write afi failed");
                    return status;
                }
            }
        }
    }

    status = rw_i93_check_ndef_writable();
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("ndef is read only");
        return status;
    }

    status = rw_i93_write_cc_ndef_tlv();
    if (status != NCI_STATUS_OK) {
        NFCLOG_E("write cc ndef tlv failed");
    }

    NFCLOG_D("exit");
    return status;
}
static tNCI_STATUS ndef_write(uint8_t *p_data, uint32_t length) {

    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tT5T_INFO *p_i93 = &s_t5t_info;
    NFCLOG_D("enter");
    if (p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) {
        if (p_i93->intl_flags & RW_I93_FLAG_READ_ONLY) {
            NFCLOG_E(" NDEF is read-only");
            status = NCI_STATUS_EXT_FAILED;
            return status;
        }
        if (p_i93->max_ndef_length < length) {
            NFCLOG_E("data (%d bytes) is more than max NDEF length (%d)",
                        length, p_i93->max_ndef_length);
            status = NCI_STATUS_EXT_FAILED;
            return status;
        }

        p_i93->ndef_length = length;
        p_i93->p_update_data = p_data;
        if (RW_I93_GET_SYS_INFO_MEM_INFO == p_i93->i93_t5t_mode) {
            status = rw_i93_ndef_reset_tlv_block();
            if (status != NCI_STATUS_OK) {
                NFCLOG_E(" reset ndef tlv block failed");
                goto exit;
            }

            status = rw_i93_ndef_write_blocks();
            if (status != NCI_STATUS_OK) {
                NFCLOG_E(" reset ndef write blocks failed");
                goto exit;
            }

            status = rw_i93_ndef_update_length();
            if (status != NCI_STATUS_OK) {
                NFCLOG_E(" update ndef length failed");
                goto exit;
            }
        } else {
            status = rw_t5t_ndef_reset_tlv_block();
            if (status != NCI_STATUS_OK) {
                NFCLOG_E(" reset ndef tlv block failed");
                goto exit;
            }

            status = rw_t5t_ndef_write_blocks();
            if (status != NCI_STATUS_OK) {
                NFCLOG_E(" reset ndef write blocks failed");
                goto exit;
            }

            status = rw_t5t_ndef_update_length();
            if (status != NCI_STATUS_OK) {
                NFCLOG_E(" update ndef length failed");
                goto exit;
            }
        }

    } else {
        NFCLOG_E(" No NDEF detected");
        status = NCI_STATUS_EXT_FAILED;
        goto exit;
    }
exit:
    NFCLOG_D("exit");
    p_i93->p_update_data = NULL;
    return status;
}

static tNCI_STATUS ndef_read(tNCI_RSP *p_ndef){
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tT5T_INFO *p_i93 = &s_t5t_info;
    tNCI_BUF *p_rsp = alloc_nci_buf(0);
    uint8_t *p_rsp_data;
    uint16_t length = 0;
    uint32_t offset = 0;
    uint32_t copy_length = 0;
    p_ndef->len = 0;

    NFCLOG_D("enter");

    if ((p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) &&
        (p_i93->ndef_length > 0)) {

        p_i93->rw_offset = p_i93->ndef_tlv_start_offset;
        p_i93->rw_length = 0;
        p_ndef->data = (uint8_t*)osi_calloc(p_i93->ndef_length);
        if (!p_ndef->data) {
            NFCLOG_E("alloc ndef data failed");
            status = NCI_STATUS_EXT_ALLOC_FAILED;
            goto exit;
        }
        while(true) {
            status = rw_i93_get_next_blocks(p_i93->rw_offset, p_rsp);
            if (status != NCI_STATUS_OK) {
                NFCLOG_E("get next block data failed");
                break;
            }
            length = p_rsp->len;
            p_rsp_data = p_rsp->data;
            length --;
            NFCLOG_D("length = %d", length);
            p_rsp_data++;

            copy_length = length;

            /* if this is the first block */
            if (p_i93->rw_length == 0) {
                /* get start of NDEF in the first block */
                offset = p_i93->ndef_tlv_start_offset % p_i93->block_size;

                if (p_i93->ndef_length < 0xFF) {
                    offset += 2;
                } else {
                    offset += 4;
                }

                /* adjust offset if read more blocks because the first block doesn't have
                * NDEF */
                offset -= (p_i93->rw_offset - p_i93->ndef_tlv_start_offset);
            } else {
                offset = 0;
            }

            /* if read enough data to skip type and length field for the beginning */
            if (offset < length) {
                // offset++; /* flags */
                p_rsp_data += offset;
                copy_length -= offset;

                p_i93->rw_length += copy_length;
            } else {
                /* in case of no Ndef data included */
                copy_length = 0;
            }

            /* if read all of NDEF data */
            if (p_i93->rw_length >= p_i93->ndef_length) {
                /* remove extra btyes in the last block */
                if (copy_length >= p_i93->rw_length - p_i93->ndef_length) {
                    copy_length -= (p_i93->rw_length - p_i93->ndef_length);
                } else {
                    NFCLOG_D("invalid copy length(%d), rw length(%d), ndef length(%d)",
                                copy_length, p_i93->rw_length, p_i93->ndef_length);
                    status = NCI_STATUS_EXT_FAILED;
                    break;
                }

                NFCLOG_D(" NDEF read complete read (%d)/total (%d)", copy_length, p_i93->ndef_length);
                NFCLOG_D("NDEF read complete, copy length(%d), rw length(%d), return ndef length(%d)",
                            copy_length, p_i93->rw_length, p_ndef->len);
                if (copy_length > 0) {
                    if (!osi_memcpy_s(p_ndef->data + p_ndef->len,
                                        p_i93->ndef_length - p_ndef->len,
                                        p_rsp_data,
                                        copy_length)) {
                        NFCLOG_E("copy ndef data failed");
                        status = NCI_STATUS_EXT_COPY_FAILED;
                        break;
                    }
                    p_ndef->len += copy_length;
                }

                status = NCI_STATUS_OK;
                break;

            } else {
                NFCLOG_D("NDEF read segment read (%d)/total (%d)", copy_length, p_i93->ndef_length);
                NFCLOG_D("NDEF read segment, copy length(%d), rw length(%d), return ndef length(%d)",
                            copy_length, p_i93->rw_length, p_ndef->len);
                if (copy_length > 0) {
                    if (!osi_memcpy_s(p_ndef->data + p_ndef->len,
                                        p_i93->ndef_length - p_ndef->len,
                                        p_rsp_data,
                                        copy_length)) {
                        NFCLOG_E("copy ndef data failed");
                        status = NCI_STATUS_EXT_COPY_FAILED;
                        break;
                    }
                    p_ndef->len += copy_length;
                }

                /* this will make read data from next block */
                p_i93->rw_offset += length;
                NFCLOG_D("read next single block, offset:(%d)", p_i93->rw_offset);
                reset_nci_buf(p_rsp);
                continue;
            }
        }
    } else if ((p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) && (p_i93->ndef_length == 0)) {
        NFCLOG_E("empty ndef message");
        status = NCI_STATUS_EXT_EMPTY_DATA;
    } else {
        NFCLOG_E("%s - No NDEF detected", __func__);
        status = NCI_STATUS_EXT_FAILED;
    }

exit:
    if (status != NCI_STATUS_OK) {
        if (p_ndef->data) {
            osi_free(p_ndef->data);
            p_ndef->data = NULL;
        }
    }
    free_nci_buf(p_rsp);
    NFCLOG_D("exit");
    return status;
}
static tNCI_STATUS ndef_detect(tNCI_RW_NDEF_INFO *p_ndef_info) {

    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tT5T_INFO *p_i93 = &s_t5t_info;
    NFCLOG_D("enter");
    if (RW_I93_GET_SYS_INFO_MEM_INFO == p_i93->i93_t5t_mode) {
        status = rw_i93_ndef_check_cc();
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("check cc failed");
            return status;
        }

        status = rw_i93_ndef_search_tlv();
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("search ndef tlv failed");
            return status;
        }

        status = rw_i93_ndef_check_lock_status();
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("check lock status failed");
            return status;
        }
    } else {
        status = rw_t5t_ndef_check_cc();
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("check t5t cc failed");
            return status;
        }

        status = rw_t5t_ndef_search_tlv();
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("search t5t ndef tlv failed");
            return status;
        }
    }

    p_ndef_info->curr_size = p_i93->ndef_length;

    if (p_i93->intl_flags & RW_I93_FLAG_READ_ONLY) {
        p_ndef_info->mode = NCI_RW_NDEF_MODE_READ_ONLY;
        p_ndef_info->max_size = p_i93->ndef_length;
    } else {
        p_ndef_info->mode = NCI_RW_NDEF_MODE_READ_WRITE;
        p_ndef_info->max_size = p_i93->max_ndef_length;
    }

    NFCLOG_I("current ndef size:%d, max ndef size:%d", p_ndef_info->curr_size, p_ndef_info->max_size);

    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS set_tag_read_only(bool is_hard_lock) {
    (void) is_hard_lock;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tT5T_INFO *p_i93 = &s_t5t_info;

    NFCLOG_D("enter");
    if ((p_i93->tlv_type == I93_ICODE_TLV_TYPE_NDEF) &&
        (p_i93->i93_t5t_mode != RW_T5T_CC_READ_MEM_INFO)) {
        if (p_i93->intl_flags & RW_I93_FLAG_READ_ONLY) {
            NFCLOG_I("NDEF is already read-only");
            return  NCI_STATUS_OK;
        }

        status = rw_i93_set_tag_read_only_if_ndef_detected();

    } else {
        if (p_i93->i93_t5t_mode == RW_T5T_CC_READ_MEM_INFO) {

            status = rw_t5t_set_tag_read_only_if_ndef_detected();

            return status;
        }
        NFCLOG_E("No NDEF detected");
        return NCI_STATUS_EXT_FAILED;
    }


    NFCLOG_D("exit");
    return status;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)

static tNCI_STATUS presence_check() {
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *p_rsp;
    tT5T_INFO *p_i93 = &s_t5t_info;
    NFCLOG_D("enter");

    if (RW_I93_GET_SYS_INFO_MEM_INFO == p_i93->i93_t5t_mode) {
        /* The support of AFI by the VICC is optional, so do not include AFI */
        status = rw_i93_send_cmd_inventory(p_i93->uid, false, 0x00);
    } else {
        /* Extended command not expected for presence check */
        p_rsp = alloc_nci_buf(0);
        if (p_rsp)
        p_i93->intl_flags &= ~RW_I93_FLAG_EXT_COMMANDS;
        status = rw_i93_send_cmd_read_single_block(0, false, p_rsp);
        free_nci_buf(p_rsp);
    }
    NFCLOG_D("exit");
    return status;
}

static tNCI_STATUS on_disconnect() {
    osi_memset_s(&s_t5t_info, sizeof(tT5T_INFO), 0, sizeof(tT5T_INFO));
    return NCI_STATUS_OK;
}
static tNCI_STATUS on_connect(tNCI_RW_TAG *p_tag) {

    uint8_t uid[I93_UID_BYTE_LEN];
    tT5T_INFO *p_i93 = &s_t5t_info;
    uint16_t afi_location, block_size;
    tNCI_STATUS status = NCI_STATUS_EXT_FAILED;
    for (int i = 0; i < I93_UID_BYTE_LEN; i ++) {
        NFCLOG_D("p_tag->uid[%d] = 0x%02x", i, p_tag->uid[i]);
    }
    osi_memset_s(p_i93, sizeof(tT5T_INFO), 0, sizeof(tT5T_INFO));
    NFCLOG_D("enter, dta mode(%d)", g_dta_mode_enabled);

    const tNFC_CF *p_cf = nfc_config_get();
    p_i93->mute_legacy = p_cf->t5t_mute_legacy;

    if (!osi_memcpy_s(uid, I93_UID_BYTE_LEN, p_tag->uid, I93_UID_BYTE_LEN)) {
        NFCLOG_E("memecpy failed");
        return status;
    }
    rw_i93_get_product_version(uid);

    if ((uid[I93_UID_MFG_CODE_IND] == I93_UID_IC_MFG_CODE_TI) &&
        (((uid[I93_UID_MFG_PROD_TYPE_IND] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) ==
          I93_UID_TAG_IT_HF_I_STD_CHIP_INLAY) ||
         ((uid[I93_UID_MFG_PROD_TYPE_IND] & I93_UID_TAG_IT_HF_I_PRODUCT_ID_MASK) ==
          I93_UID_TAG_IT_HF_I_PRO_CHIP_INLAY))) {
        /* these don't support Get System Information Command */
        block_size = I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_BLK_SIZE;
        afi_location = I93_TAG_IT_HF_I_STD_PRO_CHIP_INLAY_AFI_LOCATION;

        /* read AFI */
        tNCI_BUF *p_rsp = alloc_nci_buf(0);
        status = rw_i93_send_cmd_read_single_block((uint16_t)(afi_location / block_size), false, p_rsp);
        free_nci_buf(p_rsp);
        if (status != NCI_STATUS_OK) {
            NFCLOG_E("read afi block failed");
            return status;
        }
    } else {
        /* All of ICODE supports Get System Information Command */
        /* Tag-it HF-I Plus Chip/Inlay supports Get System Information Command */
        /* just try for others */
        if (rw_i93_check_legacy_product(uid[I93_UID_MFG_CODE_IND], uid[I93_UID_MFG_PROD_TYPE_IND])) {
            status = rw_i93_get_sys_info(uid);
            if (status != NCI_STATUS_OK) {
                NFCLOG_E("get system info failed");
                return status;
            }
            p_i93->i93_t5t_mode = RW_I93_GET_SYS_INFO_MEM_INFO;
        }
    }

    s_t5t_info.connected = true;
    NFCLOG_D("exit");
    return NCI_STATUS_OK;
}

static tNCI_STATUS check_transceive_resp(uint8_t *p_rsp, uint16_t *p_rsp_len) {
    if (!p_rsp || !p_rsp_len || 0 == *p_rsp_len) {
        NFCLOG_E("invalid param");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }

    *p_rsp_len = *p_rsp_len - 1;
    return NCI_STATUS_OK;
}

tNCI_RW_TAG_API g_rw_t5t_api = {
    .max_retry_count = NCI_RW_DEFAULT_MAX_RETRY_COUNT,
    .on_connect = on_connect,
    .on_disconnect = on_disconnect,
    .check_transceive_resp = check_transceive_resp,
    .presence_check = presence_check,
#if IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
    // .on_select = on_select,
    .ndef_detect = ndef_detect,
    .ndef_read = ndef_read,
    .ndef_write = ndef_write,
    .ndef_format = ndef_format,
    .is_ndef_formatable = is_ndef_formatable,
    .set_tag_read_only = set_tag_read_only,
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_NDEF)
};

#endif // IS_FEATURE_ON(NCI_FEATURE_RW_T5T)